[bits 32]
section .text
; -----------------------
; Function
; ------------------
; switch_to
; ------------------
; @params cur: Pointer to the current task esp
; @params next: Pointer to the next task esp to switch to
; @return: NULL
; -----------------------
global switch_to
switch_to:
   ; Stack contains the return address

   ; preserve the environment according to ABI standard
   ; esp will be saved later
   push esi                      	
   push edi
   push ebx
   push ebp

   ; Stack information 
   ;| -------- | --------------- |
   ;|   ebp    |   low address   |  <-- esp point at
   ;| -------- |                 |  
   ;|   ebx    |                 |
   ;| -------- |                 |
   ;|   edi    |                 |
   ;| -------- |                 |
   ;|   esi    |                 |
   ;| -------- |                 |
   ;| ret_addr |                 |
   ;| -------- |                 |
   ;|   cur    |                 |
   ;| -------- |                 |
   ;|   next   |  high address   |

   ; ------- backing up the current thread's environment -------
   ; Get the 'cur' parameter from the stack, cur = [esp + 5*4]
   ; now eax stores address of cur thread self_kstack member in task_struct 
   mov eax, [esp + 20]
   ; Save current thread's esp
   mov [eax], esp
   ; task_struct's self_kstack field is at offset 0 in task_struct
   ; saving 4 bytes to the beginning of the thread is sufficient

   ; ------- restoring the next thread's environment -------
   ; Get the 'next' parameter from the stack, next = [esp + 6*4]
   mov eax, [esp + 24]
   ; switch to next thead's esp
   mov esp, [eax]
   ; The first member of PCB is self_kstack member, used to record the top pointer of level 0 stack
   ; used to restore the level 0 stack, which contains all information of the process or thread when switching thread.

   pop ebp
   pop ebx
   pop edi
   pop esi
   ; Return to the ret_addr in the stack
   ret  ; if not entered by interrupt, will return to start_thread_with_func() when first executed
